library ieee;
use ieee.std_logic_1164.all;

-- This arbitrary state machine is probably not very useful in reality, but demonstrates 

entity rcv_emulator_continuous is
    port (clock               			: in  std_logic;
          reset               			: in  std_logic;
          seed                          : in  std_logic_vector(7 downto 0);
          num_frames                    : in  std_logic_vector(10 downto 0);
          --prb_out                       : out std_logic_vector(7 downto 0);
          frame_count                   : out std_logic_vector(10 downto 0);
          RCV_to_FWD_DATA				: out std_logic_vector(7 downto 0);
		  RCV_to_FWD_LENGTH				: out std_logic_vector(11 downto 0);
		  RCV_to_FWD_FRAMEAVAILABLE		: out std_logic;
		  FWD_to_RCV_LENGTH_ACK			: in  std_logic;
		  FWD_to_RCV_FRAME_ACK			: in  std_logic
	   );
end rcv_emulator_continuous;

architecture behavior of rcv_emulator_continuous is

component prbg is
    port (clock,reset         : in  std_logic;
          clock_en			  : in  std_logic;
          seed                : in  std_logic_vector(7 downto 0);
          load                : in  std_logic;
          prb                 : out std_logic_vector(7 downto 0)
    );
end component;

component countdown is
	port
	(
		aclr		: in  std_logic;
		clock		: in  std_logic;
		cnt_en		: in  std_logic;
		data		: in  std_logic_vector(10 downto 0);
		sload		: in  std_logic;
		q			: out std_logic_vector(10 downto 0)
	);
end component;

component fwd_test_countup is
	port
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		cnt_en		: IN STD_LOGIC ;
		q		    : OUT STD_LOGIC_VECTOR (10 DOWNTO 0)
	);
end component;

component rand_wait_add is
	port
	(
		dataa		: in  std_logic_vector(10 downto 0);
		result		: out std_logic_vector(10 downto 0)
	);
end component;

type   state_type is (init_state,wait_state, ack_state, length_state, data_state,load_wait_state);
signal my_state_reg, my_state_next: state_type:= init_state;
signal count_en, load, load_seed : std_logic;
signal rand_byte : std_logic_vector(7 downto 0);
signal count, l_data : std_logic_vector(10 downto 0);
signal rand_wait : std_logic_vector(10 downto 0);
signal frame_count_en : std_logic;
signal frame_count_internal : std_logic_vector(10 downto 0);

begin

-- Update state on rising edges or a reset
process(clock, reset)
	begin
		if(reset ='1') then 
		  my_state_reg <= init_state;
		elsif(clock'event and clock='1') then
			my_state_reg<=my_state_next;
		end if;
	end process;

process(my_state_reg, count, num_frames, frame_count_internal) 
	begin
	    case my_state_reg is
		    when init_state => 
		        my_state_next <= load_wait_state;
			when wait_state =>
			    if (count= "00000000000") then
					if (num_frames = frame_count_internal) then
				        my_state_next <= wait_state;
				    else
					    my_state_next <= ack_state;
					end if;
				else
					my_state_next <= wait_state;
				end if;
			when ack_state =>
				my_state_next <= length_state;
			when length_state =>
				my_state_next <= data_state;
			when data_state =>
			    --if (count= "00000000000") then
				--	my_state_next <= load_wait_state;
				--else
				my_state_next <= data_state;
				--end if;
			when load_wait_state =>
			    my_state_next <= wait_state;
		end case;
	end process;
	
process (my_state_reg,rand_byte,rand_wait)  -- Moore output logic
	begin
	    --prbg_en <= '0';
	    load_seed <= '0';
	    count_en <= '0';
	    load <= '0';
	    frame_count_en <= '0';
	    l_data <= "00000101010";
	    RCV_to_FWD_DATA <= "00000000";
	    RCV_to_FWD_LENGTH <= "000000000000";
	    RCV_to_FWD_FRAMEAVAILABLE <= '0';
		case my_state_reg is
		    when init_state =>
		        load_seed <= '1';
			when wait_state => 
				count_en <= '1';
			when ack_state => 
			    RCV_to_FWD_FRAMEAVAILABLE <= '1';
			when length_state =>
			    RCV_to_FWD_LENGTH <= "100000101010";
			    RCV_to_FWD_FRAMEAVAILABLE <= '1';
			    load <= '1';
			    frame_count_en <= '1';
			    --RCV_to_FWD_DATA <= rand_byte;
			    --prbg_en <= '1';
			when data_state => 
				--prbg_en <= '1';
				count_en <= '1';
				RCV_to_FWD_LENGTH <= "100000101010";
				RCV_to_FWD_DATA <= rand_byte;
				RCV_to_FWD_FRAMEAVAILABLE <= '1';
			when load_wait_state =>
			    load <= '1';
			    l_data <= rand_wait;
		end case;
	end process;

gen: prbg port map(clock,reset,'1',seed,load_seed,rand_byte);
counter: countdown port map(reset,clock,count_en,l_data,load,count);
add: rand_wait_add port map( "00000011111" and rand_byte, rand_wait);
frame_counter: fwd_test_countup port map(reset,clock,frame_count_en,frame_count_internal);

frame_count <= frame_count_internal;
--prb_out <= rand_byte;

end behavior;